package com.hmall.gateway.routers;

import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteLoader {

    private final NacosConfigManager nacosConfigManager;

    private final String dataId="gateway-routes.json";

    private final String group = "DEFAULT_GROUP";

    private final RouteDefinitionWriter writer;

    //记录路由 set保证不重复
    private final Set<String> routeIds=new HashSet<>();

    //项目启动先拉去一次配置，并且添加配置监听器
    @PostConstruct
    public void initRouter() throws NacosException {
        String configInfo=nacosConfigManager.getConfigService()
                .getConfigAndSignListener(dataId, group, 5000, new Listener() {
                    @Override
                    public Executor getExecutor() {
                        return null;
                    }

                    @Override
                    public void receiveConfigInfo(String configInfo) {
                        //监听到配置变更，需要更新路由表
                        updateConfigInfo(configInfo);
                    }
                });
        //第一次读取到配置，也需要更新到路由表
        updateConfigInfo(configInfo);
    }

    public void updateConfigInfo(String configInfo){
        log.info("监听路由信息{}",configInfo);
        //解析配置信息转换为RouteDefinition
        List<RouteDefinition> routeDefinitionList= JSONUtil.toList(configInfo,RouteDefinition.class);

        //删除原先的路由表，根据id
        for(String routeId:routeIds){
            writer.delete(Mono.just(routeId)).subscribe();
        }
        //清空路由表
        routeIds.clear();
        //更新路由表
        for(RouteDefinition routeDefinition:routeDefinitionList){
            writer.save(Mono.just(routeDefinition)).subscribe();
            //添加进路由表
            routeIds.add(routeDefinition.getId());
        }
    }
}
